<?php

declare(strict_types=1);

namespace coder;

/**
 * 代码构建器
 */
class Builder
{

	/**
	 * 原始文本
	 * @var string
	 */
	protected string $origin_contents;
	/**
	 * 变量清单
	 * @var array
	 */
	protected array $var_list = [];

	/**
	 * 读取stub文件到实例内容中
	 * @param string $name stub文件名（不含后缀）
	 * @return $this
	 */
	public function loadStub($name)
	{
		$path = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . $name . '.stub';
		$contents = file_get_contents($path);
		$this->setOriginContents($contents);
		return $this;
	}
	public function setOriginContents(string $contents = null)
	{
		$this->origin_contents = $contents;
		return $this;
	}
	public function getOriginContents()
	{
		return $this->origin_contents;
	}
	public function setVarList($list, $append = false)
	{
		$this->var_list = $append ? array_merge($this->var_list, $list) : $list;
		return $this;
	}
	public function getVarList()
	{
		return $this->var_list;
	}

	/**
	 * 生成结果内容
	 */
	public function build(): string
	{
		return static::buildResult($this->getOriginContents(), $this->getVarList());
	}

	/**
	 * 生成结果并保存为文件
	 * @param string $dir 保存路径
	 * @param string $filename 保存的文件名（含后缀）
	 * @param boolean $force 是否强制覆盖
	 * @return self
	 */
	public function save(string $dir, string $filename, $force = false): self
	{
		static::createFile($dir, $filename, $this->build(), $force);
		return $this;
	}

	/**
	 * 创建文件
	 * @param string $dir 目录
	 * @param string $name 文件名（含后缀）
	 * @param boolean $force 是否强制覆盖
	 * @param string $contents 文件要写入的内容
	 * @return string|false 完整的文件路径
	 */
	public static function createFile(string $dir, string $filename, $contents = null, bool $force = false)
	{
		$fullName = $dir . $filename;
		if (file_exists($fullName) && !$force) {
			// throw new \Exception('文件已存在');
			return false;
		}

		if (!is_dir($dir)) {
			mkdir($dir, 0777);
		}
		file_put_contents($fullName, $contents);
		return $fullName;
	}

	/**
	 * 正则替换生成结果
	 * @param string $originContents 原始内容
	 * @param array $varList 要替换的变量数组
	 * @return string 内容
	 */
	public static function buildResult(string $originContents, array $varList): string
	{
		return preg_replace_callback("/(?:\{%)(.*?)(?:%\})/i", function ($it) use ($varList) {
			extract($varList);
			$varName = $it[1];
			if (!isset($$varName)) {
				return $it[0];
			}
			return $$varName;
		}, $originContents);
	}
}
